The Official Free Version Of Bage Wubi Typist

The official free version of Bage Wubi Typist is a very powerful computer typing software. The software interface design is simple and capable. It is mainly created for novices to learn and practice typing. It is very rich in functions. Users can practice typing and improve their typing speed through mouse exercises, fingering teaching, English tests, five-stroke exercises and other methods. Come and try it now!

How to use the official free version of Bage Wubi Typist

Function home page

Fingering teaching

Introduction to the official free version of Bage Wubi Typist

The official free version of Bage Wubi Typist has a beautiful interface, simple use and complete functions. It is the most useful Wubi typing teaching software in China! The official free version of Bage Wubi Typist provides a variety of Chinese character input methods for you to choose from, including Wubi input method version 86, Wubi input method 98 version, Erbi input method, Shuangpin input method, and popular phonetic input method. Please click on the "Help" ” to select your favorite input method.

Highlights of the official free version of Bage Wubi Typist

Fingering practice: animated teaching, standard touch typing fingering tips.

Typing practice: provides a quick tutorial, no need to read the book, press the F1 key to instantly prompt Wubi coding, coding rules, and root splitting.

Article test: Dynamic prompts for phrases, typing words when they are seen, typing single Chinese characters if they do not form a phrase, real-time coding help, and providing three test methods: fixed speed test, timed test, and quantitative test. In particular, explosion animations and sounds are provided during the test, making the boring article test equally fun (every time a word or word is typed correctly, the word or word will explode).

Even more interesting: In addition to providing a mosquito-killing game, it also integrates the software "Tintin Wubi Dictionary" and "Tintin Chinese Chess".

Features of the official free version of Bage Wubi Typist

1. Standard fingering animation teaching helps you master the most correct fingering from the beginning and improve your typing speed throughout your life.

2. Wubi 86 version and Wubi 98 version typing instruction from easy to deep, real-time prompts for Wubi coding, coding rules, character root splitting, and an original hollow character stroke prompt function, truly making learning easy and fast master.

3. Article practice provides three practice methods: timed, quantitative, and fixed speed. The phrase prompts and article listening and typing functions can truly improve the practical ability of Wubi typing.

4. The principle is completely free, without any functional restrictions; whether you are just starting to learn Wubi, or you have a certain foundation in Wubi and want to further improve your typing speed, this software will bring you great benefits.

Highlights Of Shuangpin Input Method Software

Shuangpin input method version is a comprehensive and very practical computer input method software. Shuangpin input method version is improved from XP’s Shuangpin input method 5.0. The software is highly compatible and can support XP, and supports Windows 7 systems. , Shuangpin input method is simple, easy to learn and efficient, and is the best choice for users to improve their spelling input speed.

Highlights of Shuangpin input method software

Shuangpin input method is improved from XP's Shuangpin input method 5.0, supports XP, and supports Windows 7 systems;

This Shuangpin input method still has a traditional interface. The system comes with the Shuangpin 5.0 vocabulary library, so you don’t need to change your habits.

The Shuangpin input method runs very stably and has passed the test on XP, Win7 systems.

Shuangpin input method installation steps

1. We download the Shuangpin input method software, obtain a compressed package, decompress it, and obtain this exe file.

3. If the software is installed successfully, click OK to end the software installation.

Shuangpin input can:

1. It has the screen function of adapting to various resolutions and supports various touch screen models, such as VGA, WVGA, QVGA, etc.

2. Supports the keyboard panel to be freely enlarged. Including automatic stretching of horizontal screen and free setting of vertical screen to better meet the needs of different people and different screens.

3. Supports free replacement of keyboard panel skin to better meet different personalized requirements for the interface. The system has four built-in exquisite panel skins for users to choose from. Users can also define their own keyboard panel skin. DIY can be realized by modifying the skin image file. (If there is a player who makes a beautiful keyboard panel skin, please remember to share it with everyone!)

4. Provides 6 built-in font selection functions. Better meet the needs of different people in different situations.

5. It has a key sound prompt function option, which can sound simultaneously when the keys are pressed to achieve better input physical examination.

The popular two-code input method supports various Chinese character encodings input in spelling format, such as Wubi (including version 86 and version 98), Erbi, and Liangchi. We have developed different series of products for different encodings. Except for different Chinese character encodings, the input method functions of different series of products are basically the same. Users must choose the correct product for installation according to the actual situation when installing and using it.

Based On Java Basics – Object-oriented Implementation Of Plants Vs. Zombies Simple Version

Based on Java basics – object-oriented implementation of Plants vs. Zombies simple version

Preface

In the first month of learning Java from scratch, during object-oriented (OOP) learning, I followed the instructor to complete the game coding of Airplane Battle. I started to get in touch with the API in the second month. On a whim, I combined the collections and multi-threading in the API to start coding Plants vs. Zombies. It took about 2 weeks from the design of the game mode to the implementation of the game content. This is my 7th month of exposure to Java. Looking back at the works that I was proud of and even helped me get an offer to a certain extent, the code seems immature and jerky. I originally wanted to revamp the code and add some unfinished features, but I couldn't bear to do it. After all, it was my first complete work. So I wanted to share the design ideas and game code, and communicate and learn with everyone.

game design

There is a mini-game level in Plants vs. Zombies. There is a roller machine directly above the screen, which will randomly generate plants. Players can select the plants and freely choose the lawn to place them. Based on this game mode, I extracted this level and made it into a simple version of Plants vs. Zombies.The game screen is roughly as follows

Plant cards will be automatically generated on the left side of the screen. Click to select and place them on the lawn. Zombies will be automatically generated on the right side. Different zombies move at different speeds and have different blood volumes. Some zombies have hidden rewards, such as: full-screen zombies are still, full-screen zombies are dead, etc. At that time, there was no function to pause the game, which makes it difficult to control the timing of taking screenshots now. So let’s first talk about how to implement the function of pausing the game.

The simplest way to pause is to move the mouse off the screen and the game will pause. So here you need to introduce a mouse listener event.

public void mouseMoved(MouseEvent e) {
	// 当游戏处于运行状态时
	if (status == start) {
		// 通过鼠标移动事件的对象获取当前鼠标的位置
		int x = e.getX();
		int y = e.getY();
		// 如果鼠标超出了游戏界面
		if (x > Game.WIDTH || y > Game.HEIGHT) {
			// 将游戏的状态改为暂停状态
			status = pause;
		}
	}
}

Of course, this is just a simple method of changing the game state by listening to the mouse position. You can also use a keyboard listener to pause the game when a certain key is pressed, which provides a better user experience. But the principle is the same, so the code will not be shown here.

game object

First analyze what objects are in the game. All kinds of plants, all kinds of zombies, all kinds of bullets. Then you can extract three parent categories here, namely plants, zombies, and bullets. In object-oriented, the subclass will inherit all the properties and methods of the parent class. Therefore, the common attributes and methods in the three major categories can be extracted into their respective parent classes.For example, the zombie parent class

public abstract class Zombie {
	// 僵尸父类 
	// 僵尸共有的属性
	protected int width;
	protected int height;
	protected int live;
	protected int x;
	protected int y;
	......
	// 僵尸的状态
	public static final int LIFE = 0;
	public static final int ATTACK = 1;
	public static final int DEAD = 2;
	protected int state = LIFE;
	/* 
	* 这里补充一下为什么父类是抽象类,比如每个僵尸都有移动方法,
	* 但每个僵尸的移动方式是不同,所以该方法的方法体可能是不同的,
	* 抽象方法没有方法体,在子类中再去进行重写就可以了,
	* 但有抽象方法的类必须是抽象类,因此父类一般都是抽象类
	*/ 
	// 移动方式
	public abstract void step();
	....
}

The same applies to the plant parent class and the bullet parent class.

It is mentioned above that the methods common to subclasses need to be extracted to the parent class, so how to deal with the methods common to some subclasses? For example, Pea Shooter and Ice Shooter can shoot bullets, but Nut Wall does not have this behavior. So you need to use interface() here.

public interface Shoot {
	// 射击接口 - 将部分子类共有的行为抽取到接口中
	// 接口中的方法默认是public abstract的,规范的编码应该将该字段舍去
	public abstract Bullet[] shoot();
}

So far, the properties and methods of the game object have basically been defined. As for the display of pictures and how to draw pictures, you only need to use the corresponding API, which will not be described here. After working for a year, I look back and see that there are still many places that can be optimized. For example, the object's health, attack power, movement, etc. can all be written into the configuration file. This way, when adjusting game parameters, there is no need to go To modify code-related content, you only need to modify the parameters in the configuration file.

Game content

Now that we have the game objects, it's time to start adding the objects to the game, then make them move, and finally make them fight.First, this is how I add objects to the game. Here we take zombies as an example.

// 首先有要一个僵尸的集合
// 僵尸集合
private List zombies = new ArrayList();
// 接着定义随机生成僵尸方法
public Zombie nextOneZombie() {
		Random rand = new Random();
		// 控制不同种类僵尸出现的概率
		int type = rand.nextInt(20);
		if(type<5) {
			return new Zombie0();
		}else if(type<10) {
			return new Zombie1();
		}else if(type<15) {
			return new Zombie2();
		}else {
			return new Zombie3();
		}
}
// 僵尸入场
// 设置进场间隔
/*
* 这里补充一下为什么要设置进场的间隔
* 因为游戏的运行是基于定时器的,
* 每隔一段时间定时器就会执行一次你所加入定时器的方法,
* 所以这里需要设置进场间隔来控制游戏的速度。
*/
int zombieEnterTime = 0;
public void zombieEnterAction() {
	zombieEnterTime++;
	    // 对自增量zombieEnterTime进行取余计算
		if(zombieEnterTime%300==0) {
			// 满足条件就调用随机生成僵尸方法,并将生成的僵尸加入到僵尸的集合中
			zombies.add(nextOneZombie());
		}
}

The first data structure I used was an array, but in subsequent coding I found that there were a lot of traversals and addition and deletion operations on zombie objects. The addition and deletion operations of arrays were very troublesome and complicated, so I changed to a set. The same is true at work. Thinking first before coding, and choosing the correct data structure can often get twice the result with half the effort.

The design of the entrance of plants was a point that I thought was very subtle at the time. Let me first talk about the problems found in the coding at that time. First of all, plants are on a roller machine when they enter the plant. Movement on the roller machine involves issues of pursuit and stopping. The way to pursue is of course to pursue the previous plant card, but when the first plant card is selected and placed on the grass, how to pursue it? At first, my approach was to add a few more states to the plants to solve this problem, but I found that too many states would cause the conditions in the if judgment to be greatly increased, and after trying, I still did not achieve the desired effect, so I added the plants The collection was divided into two. In the subsequent game function design, I looked back and found that dividing the plant collection into the collection on the roller machine and the collection on the battlefield was really exquisite. Please listen to me.

// 滚轮机上的植物,状态为stop和wait
private List plants = new ArrayList();
// 战场上的植物,状态为life和move -move为被鼠标选中移动的状态,这里设计不合理,会引发后面的一个BUG
private List plantsLife = new ArrayList();
// 植物在滚轮机上的碰撞判定
public void plantBangAction() {
		// 遍历滚轮机上植物集合,从第二个开始
		for(int i=1;i0&&plants.get(0).isStop()) {
				plants.get(0).goWait();
			}
			// 如果第i个植物y小于i-1个植物的y+height,则说明碰到了,改变i的状态为stop
			if((plants.get(i).isStop()||plants.get(i).isWait())&&
					(plants.get(i-1).isStop()||plants.get(i-1).isWait())&&
					plants.get(i).getY()plants.get(i-1).getY()+plants.get(i-1).getHeight()) {
				plants.get(i).goWait();
			}
		}
	}
	// 检测滚轮机上的植物状态
	public void checkPlantAction1() {
		// 迭代器
		Iterator it = plants.iterator();
		while(it.hasNext()) {
			Plant p = it.next();
			/*
			 * 如果滚轮机集合里有move或者life状态的植物
			 * 则添加到战场植物的集合中,并从原数组中删除
			 */
			/*
			* 现在发现把滚轮机上move状态的植物添加到
			* 战场上植物集合的最佳操作时间点应该是
			* 等植物状态变为life后再添加。
			* /
			if(p.isMove()||p.isLife()) {
				plantsLife.add(p);
				it.remove();
			}
		}
	}

Of course, the code for judging the plant status on the roller machine still seems awkward. It was when I wanted to optimize this code that I came up with the idea of ​​sharing the game design process and game code.So let’s talk about how to optimize this code

// 先对状态做下说明
// wait - 植物卡牌在滚轮机上移动状态,因为是等着被鼠标选中,所以取名为wait
// stop - 植物卡牌在滚轮机上停止状态,有两种情况,1 - 到顶了 2 - 撞到上一个卡牌了
// 开始对以下代码进行优化
// 如果第i个植物y小于i-1个植物的y+height,则说明碰到了,改变i的状态为stop
//			if((plants.get(i).isStop()||plants.get(i).isWait())&&
//					(plants.get(i-1).isStop()||plants.get(i-1).isWait())&&
//					plants.get(i).getY()<=plants.get(i-1).getY()+plants.get(i-1).getHeight()
//					) {
//				plants.get(i).goStop();
//			}
// 优化后的代码是这样的
// 将一个复杂的boolean拆成多个if条件
if (!(plants.get(i).isStop()||plants.get(i).isWait()) {
	break;
}
if (!(plants.get(i-1).isStop()||plants.get(i-1).isWait())) {
	break;
}
if (!(plants.get(i).getY()<=plants.get(i-1).getY()+plants.get(i-1).getHeight())) {
	break;
}
plants.get(i).goStop();

Of course the conditions can also be optimized, and the state of the plants can even be simplified. Due to the rules of the game, zombies can only attack plants on the lawn, so it is very reasonable and subtle to divide the placed plants and the plants on the lawn into two sets. To determine whether zombies attack plants, you only need to traverse the plant collection on the lawn. If it is not split, when it is necessary to determine whether zombies attack plants, the collection that needs to be traversed will be the collection of all plants, and at least 2 states need to be added to distinguish whether the plants are on the lawn or on the roller. Think about this code. It's just smelly and long.

Next it’s time to get the objects moving. As mentioned before, the movement method in the parent class is an abstract method. After rewriting them in their respective subclasses, there are various ways to move objects.

// 子弹移动
public void BulletStepAction() {
	for(Bullet b:bullets) {
		b.step();
	}
}
//僵尸移动
//设置移动间隔
int zombieStepTime = 0;
public void zombieStepAction() {
	if(zombieStepTime++%3==0) {
		for(Zombie z:zombies) {
			//只有活着的僵尸会移动
			if(z.isLife()) {
				z.step();
			}
		}
	}
}

Looking at the complex traversal of collections in the code, I have to realize that expressions are really a good thing.

// 子弹移动
public void BulletStepAction() {
	bullets.forEach((b)->b.step());
	....
}

It seems that I still can't show the powerful function of expressions here. Please see the following example.

// 为了应对产品不断变更的需求,前辈们总结经验得出的设计模式已经能在一定程度上应对此问题
// 设计模式,声明策略接口,在实现类中完成过滤逻辑
public List filterStudentByStrategy(List students, SimpleStrategy strategy){
       List filterStudents = new ArrayList();
       for (Student student : filterStudents) {
           if(strategy.operate(student)){
               filterStudents.add(student);
           }
       }
       return filterStudents;
}
// 当需求变更时,只需要在策略接口的实现类中,变更判断逻辑即可
public interface SimpleStrategy {
    public boolean operate(T t);
}

But it still seems a bit troublesome. You have to write interfaces and implementation classes. Subsequent maintenance is also a headache. At this time, the savior expression appears.

// 无需接口便可实现需求的快速变更
List lambdaStudents = 
  students.stream().filter(student -> student.getGender()==1).collect(Collectors.toList());

Let's see what's going on above. First, the data collection is streamed, and then the filtering method is called. Powerful expressions make the code concise, and the modification of the judgment conditions can be directly maintained in the code without maintaining the implementation class of the strategy interface. Finally, it is converted into a collection and a collection that meets the product requirements is returned.

Back to the topic, how to make the objects fight?Let’s take zombies attacking plants as an example:

// 僵尸的超类中定义了僵尸的攻击方法,
// 由于僵尸们的攻击行为是相同,所以这里是普通方法
// 僵尸攻击植物
public boolean zombieHit(Plant p) {
		int x1 = this.x-p.getWidth();
		int x2 = this.x+this.width;
		int y1 = this.y-p.getHeight();
		int y2 = this.y+this.width;
		int x = p.getX();
		int y = p.getY();
		return x>=x1 && x=y1 && y<=y2;
}

Combined with the pictures, the above code should be easier to understand. The black box P represents the plant, and the black box Z represents the plant. The dotted line refers to the limit distance of contact between the two. When the zombie enters the dotted line, it is guaranteed to attack the plant.

// 僵尸攻击
// 设置攻击间隔
int zombieHitTime = 0;
public void zombieHitAction() {
	if(zombieHitTime++0==0) {
		for(Zombie z:zombies) {
			// 如果战场上没有植物,则把所有僵尸的状态改为life
			/*
			* 这里补充一下为什么要先将所有的僵尸的状态先改成life状态,也就是移动状态
			* 因为下面对僵尸是否攻击的植物的判断,是从遍历战场上的植物集合开始的
			* 假如有只僵尸在吃植物,把战场上唯一的一个植物吃掉了,
			* 那么僵尸的状态将从攻击改成移动呢?
			* 所以这里运用了逆向的思想,先将所有的僵尸改为移动状态
			* 如果符合攻击的条件,那么在改为攻击状态,
			* 即便是战场上没有植物,那么僵尸还依然是移动的状态
			*/
			if(!z.isDead()) {
				z.goLife();
			}
			// 这里应该有个对战场上植物集合的判断在进行遍历
			for(Plant p:plantsLife) {
				// 如果僵尸是活的,并且植物是活的,并且僵尸进入攻击植物的范围
				/*
				* 这里有个BUG,僵尸竟然会攻击鼠标选中还未放下的植物,
				* 所以下面的判断条件中应该还需要移除被鼠标选中状态下植物
				*/
				if(z.isLife()&&!p.isDead()&&z.zombieHit(p)&&!(p instanceof Spikerock)) {
					// 僵尸状态改为攻击状态
					z.goAttack();
					// 植物掉血
					p.loseLive();
				}
			}
		}
	}
}

If there is some effect offset, the cause is the coordinate offset caused by the different sizes of the pictures. Because the pictures are all found online, the effect is not ideal.

At this point, the basic functions of the game have been basically implemented. Java is an object-oriented language. Everything is an object, features are attributes, and behaviors are methods. Zombies, plants, and lawns that can be seen with the naked eye are all objects. The characteristics of objects such as blood volume and movement speed are attributes, and the behaviors of objects such as movement, attack, and death are methods.

Let’s talk about the optimization of game functions.

Game optimization Optimization of plant placement

No more plants can be placed on grassland where plants have already been placed. Previously, the grassland was designed to be in two states: empty and hold. Now it seems that all it takes is to return a true and a false, and the entire plant collection is defined as a virtual collection.

Optimization to remove plants

The design idea is to add a shovel object.

// 铲子集合
private List shovels = new ArrayList();
// 铲子入场
public void shovelEnterAction() {
	// 铲子只有一把
	if(shovels.size()==0) {
		shovels.add(new Shovel());
	}
}
// 使用铲子
Iterator it = shovels.iterator();
Iterator it2 = plantsLife.iterator();
while(it.hasNext()) {
	Shovel s = it.next();
	// 如果铲子是移动状态,就遍历植物集合
	if(s.isMove()) {
		while(it2.hasNext()) {
			Plant p  = it2.next();
			int x1 = p.getX();
			int x2 = p.getX()+p.getWidth();
			int y1 = p.getY();
			int y2 = p.getY()+p.getHeight();
			if((p.isLife()||((Blover) p).isClick())&&Mx>x1&&Mxy1&&My<y2&&shovelCheck) {
				// 移除植物
				it2.remove();
				// 移除铲子
				it.remove();
				shovelCheck = false;
			}
		}
	}
}

Looking at this extremely complicated and seemingly powerful code, I had the idea of ​​​​taking violent action, but in order to maintain the originality, I held back. So a BUG was discovered. If after selecting the shovel, the only plant on the battlefield is eaten by zombies, then the shovel will always follow the mouse and cannot achieve the effect of elimination after use. The solution is of course very simple. When the size of the plant collection on the battlefield is 0, just clear the shovel collection.

Optimization of game playability

The types of rewards that may be obtained randomly after killing zombies mentioned above in the game design are implemented in this way. Let’s start with design analysis. Not all types of zombies can be rewarded, so the rewards should be placed in the interface.

public interface Award {
	// 奖励接口
	/*
	* 这里还是存在代码不规范的问题
	* 接口的方式默认是public abstract
	* 接口中的变量默认是public static final
	* 这些默认的字段应该舍去
	*/
	// 全屏静止
	public static final int CLEAR = 0;
	// 全屏清除
	public static final int STOP = 1;
	public abstract int getAwardType();
}

When a zombie dies, it is necessary to determine whether the zombie has a reward interface, and if so, execute the corresponding reward method.

// 检测僵尸状态
public void checkZombieAction() {
	// 迭代器
	Iterator it = zombies.iterator();
	while(it.hasNext()) {
		Zombie z = it.next();
		// 僵尸血量小于0则死亡,死亡的僵尸从集合中删除
		if(z.getLive()<=0) {
			// 判断僵尸是否有奖励的接口
			if(z instanceof Award) {
				Award a = (Award)z;
				int type = a.getAwardType();
				switch(type) {
				case Award.CLEAR:
					for(Zombie zo:zombies) {
						zo.goDead();
					}
					break;
				case Award.STOP:
					for(Zombie zom:zombies) {
						zom.goStop();
						timeStop = 1;
						//zombieGoLife();
					}
					break;
				}
			}
			z.goDead();
		    it.remove();
		}
		// 僵尸跑进房子,而游戏生命减一,并删除僵尸
		if(z.OutOfBound()) {
			gameLife--;
			it.remove();
		}
	}
}

Add game background music

BGM is one of the souls of a game. Here to add background music to the game, my choice is to create a new thread specifically to perform music parsing and playback.

// 启动线程加载音乐
Runnable r = new zombieAubio("bgm.wav");
Thread t = new Thread(r);
t.start();
public class zombieAubio implements Runnable{
	// 读音频WAV格式专用线程
	private String filename;
	public zombieAubio(String wavfile){
	    filename=wavfile;
	}
	......

It should be noted here that the API for parsing music in Java only supports WAV format files, and most music players can convert file formats.

Subsequent optimization

1. Expansion of plant species and realization of corresponding functions

For example, the most lethal corn cannon. It requires 4 small corns to synthesize. When judging whether the corn cannon can be synthesized, it is necessary to traverse the plant collection to determine the coordinates. Therefore, it is recommended that the plants that can be synthesized are placed in a separate collection, so that in It will be much simpler to make a synthesis judgment. When the size of the collection is less than 4, it will prompt that the synthesis failed. The same goes for the design of frozen watermelon.

2. The addition of action zombies, such as pole vaulting zombies, dancing zombies, etc.

Let’s talk about the design idea of ​​pole vaulting zombies. Compared with other zombies, this type of zombie has an extra jumping behavior, so it will have a separate method and separate state. Moreover, the jump can only be triggered once, so the state change of the pole vaulting zombie should be walking -> jump over when encountering a plant -> start attacking when encountering a plant again. When executing the state change, you should consider the current state. Is it still possible to jump?

3. When there are no zombies within the attack range of the plant, the plant stops attacking.

This is simple. When the plant executes the attack method, just check whether there are zombies with the same Y coordinate.