I'm an undergrad and in one of my classes, we have this assignment to make the Asteroids game (you know, the retro one!) on Processing (which is basically a simplified Javascript program). I have the code for a button:
void setup()
{
size(1280, 720);
}
void draw()
{
background(0,0,0);
drawButton();
}
Boolean pointIsInRectangle(int left, int top, int right, int bottom, int pointX, int pointY)
{
if (pointX >= left
&& pointX <= right
&& pointY <= bottom
&& pointY >= top
)
return true;
else
return false;
}
void drawButton()
{
int left = 350;
int top = 145;
int right = 860;
int bottom = 220;
rectMode(CORNERS);
color background = color(0,0,0);
if (pointIsInRectangle(left,top,right,bottom,mouseX,mouseY))
{
background = color(255);
}
// draw outer rectangle
stroke(255);
fill(background);
rect(left,top,right,bottom);
// draw caption
fill(255);
textSize(100);
text(" ASTEROIDS", left,bottom);
}
and I have the preliminary code for the ship for the game, but I need the button to get to an "in between" page so that when the button is clicked, it leads to a new screen that says "click anywhere to play game" and when any point in the screen is clicked, the ship appears and asteroids begin appearing and the game begins. HOW DO I GET THE BUTTON TO LEAD TO A NEW PAGE, AND HOW DO I CREATE THAT PAGE? I really cannot figure it out. Crossing my fingers that someone will be able to give me some guidance!!!!!
The actual result I'm seeing is that nothing is happening when the button is clicked. This makes sense because I don't know how to add the next page that says Click to Play Game, so this is the issue I'm facing. The code I have so far can be found above.
This is not question about a button, but about a game engine with multiple scenes.
Your game is a collection of screens (scenes). Every scene have definition of visuals, definition of logic, and definition of switch for another scene.
Here is the minimal solution of Your problem.
1 - Define visuals of Your screens in .display() method,
2 - Define logic condition for next screen switch in stateCondition().
boolean mouseReleased;
GameScreen screen;
GameScreen splashScreen;
GameScreen inBetweenPage;
void setup() {
size(1280, 720);
GameScreen splashScreen = new SplashScreen();
GameScreen inBetweenPage = new InBetweenPage();
splashScreen.setNextScreen(inBetweenPage);
inBetweenPage.setNextScreen(splashScreen);
screen = splashScreen;
mouseReleased = false;
}
void draw() {
screen.display();
if (screen.stateCondition()) {
screen = screen.getNextScreen();
}
}
interface GameScreen {
/**
** screen visual definition
**/
void display();
/**
** screen change state condition
**/
boolean stateCondition();
void setNextScreen(GameScreen scr);
GameScreen getNextScreen();
}
class SplashScreen implements GameScreen {
GameScreen nextScreen;
int left = 350;
int top = 145;
int right = 860;
int bottom = 220;
void display() {
background(0, 0, 0);
rectMode(CORNERS);
color background = color(0, 0, 0);
if (pointIsInRectangle(left, top, right, bottom, mouseX, mouseY)) {
background = color(255, 255, 255, 160);
}
// draw outer rectangle
stroke(255);
fill(background);
rect(left, top, right, bottom);
// draw caption
fill(255);
textSize(100);
textAlign(CENTER, CENTER);
text("ASTEROIDS", (left+right)/2, (top+bottom)/2-16);
}
boolean stateCondition() {
if (mouseReleased && (mouseButton == LEFT)) {
mouseReleased = false;
return pointIsInRectangle(left, top, right, bottom, mouseX, mouseY);
}
return false;
}
GameScreen getNextScreen() {
return nextScreen;
}
void setNextScreen(GameScreen target) {
this.nextScreen = target;
}
}
class InBetweenPage implements GameScreen {
GameScreen nextScreen;
int left = 0;
int top = 0;
int right = width;
int bottom = height;
void display() {
background(0, 0, 0);
// draw caption
fill(255);
textSize(24);
textAlign(CENTER, CENTER);
text("< click anywhere to play game >", width/2, height/2);
}
boolean stateCondition() {
if (mouseReleased && (mouseButton == LEFT)) {
mouseReleased = false;
return pointIsInRectangle(left, top, right, bottom, mouseX, mouseY);
}
return false;
}
GameScreen getNextScreen() {
return nextScreen;
}
void setNextScreen(GameScreen target) {
this.nextScreen = target;
}
}
Boolean pointIsInRectangle(int left, int top, int right, int bottom, int pointX, int pointY) {
if (pointX >= left && pointX <= right && pointY <= bottom && pointY >= top) {
return true;
} else
return false;
}
void mouseReleased() {
mouseReleased = true;
}
There is a relatively simple solution to this problem, which would be to make some space for a special "splashscreen" state in your code. It would almost be ninja coding to implement it, although in this case as you are learning it's not taking shortcuts but more like climbing a new step in the learning stairwell. Here's a proof of concept which shows what I'm speaking about:
// this boolean keeps track of the current game state: splashscreen or not
boolean splashScreen = true;
void setup() {
size(600, 400);
}
void draw() {
background(0);
// if the game has yet to start, show the splashscreen
if (splashScreen) {
drawSplashScreen();
} else {
playGame();
}
}
// this method draws the splashScreen
// it could be coded in the 'draw()' method, but it's easier to read this way
void drawSplashScreen() {
textAlign(CENTER);
textSize(30);
fill(255);
text("THIS IS THE SPLASHSCREEN \n click anywhere to play the game", width/2, height/2);
}
// this method contains everything your game loop needs to work
void playGame() {
textAlign(CENTER);
textSize(40);
fill(200, 0, 200);
text("YOU ARE CURRENTLY \n PLAYING THE GAME", width/2, height/2);
}
void mouseClicked() {
if (splashScreen) {
splashScreen = !splashScreen;
}
}
Here you have 2 game states: the splash screen and the game itself, but you could implement more than just these two. There's a design pattern called Finite State Machine that would be just perfect for your needs. Although you already have everything you need to code your assignment, let me explain a little further:
A FSM let you determine the context which can lead to another context and limit some actions to it's own context. A good example of this is Mario in the original Super Mario Bros game: when he's small, getting a magic mushroom will transform him into Super Mario. When he's Super, getting a flower will transform him into Fire Mario. But while small, getting a flower will only make him into Super Mario, not Fire Mario (in the ooold first game at least). That's because each one of these states have rules, and he cannot just jump from one to the other without regard for these.
Your game's logic has it's own rules too: you have the first screen with the "start" button. When this button is clicked, there's a second state where it says "click anywhere to play the game". If the user clicks, then the game itself starts. That makes for 3 states (3 screens if you like) where every state has it's own set of rules - which we often call 'business rules'.
We could schematize this assignment like this:
And here's the skeleton code that would implement such a game, including a bonus rectangle collision detection method:
// the game states are as follow:
// 0 is welcome screen with button
// 1 is click anywhere screen
// 2 is the game itself
int gameState = 0;
void setup() {
size(600, 400);
}
void draw() {
background(0);
// let's use the right game state here
switch(gameState) {
case 0:
drawWelcomeScreen();
break;
case 1:
drawClickAnywhereScreen();
break;
case 2:
playGame();
break;
}
}
void drawWelcomeScreen() {
fill(0, 0, 100);
rect(100, 100, 400, 100);
textAlign(CENTER);
textSize(30);
fill(255);
text("Click here to play", 300, 150);
text("THIS IS THE WELCOME SCREEN", width/2, 50);
}
void drawClickAnywhereScreen() {
textAlign(CENTER);
textSize(30);
fill(255);
text("Click anywhere to play the game", width/2, height/2);
}
void playGame() {
textAlign(CENTER);
textSize(40);
fill(200, 0, 200);
text("YOU ARE CURRENTLY \n PLAYING THE GAME \n click anywhere to go \n back to the welcome screen", width/2, height/2);
}
void mouseClicked() {
// now this will be more complicated, because you'll want to deal with clicks differently depending on the game state
// which kinda answers the question as how we'll deal with this issue: same as in the 'draw()' method
switch(gameState) {
case 0:
// if the click's coordinates are in the rectangle's coordinates (use math here, or a collision method)
// (in fact, use math pretty much everywhere)
// (I hope you like math)
// anyway here's an old collision method I paste everywhere on SO, feel free to steal it and improve on it!
// I wrote it as a student to deal with pretty much the same stuff that you're going through
if (intersect(100, 100, 400, 100, mouseX, mouseY, 1, 1)) {
gameState = 1;
}
break;
case 1:
gameState = 2;
break;
case 2:
gameState = 0;
break;
}
}
// enter the xy coordinates, the width and the heigh of 2 rectangle shapes and it'll return true if they intersect
boolean intersect(float x1, float y1, float w1, float h1, float x2, float y2, float w2, float h2) {
boolean checkX = false;
boolean checkY = false;
if ( (x1<x2 && (x1+w1)>x2) || (x1<(x2+w2) && (x1+w1)>x2+w2) || (x1>x2 && (x1+w1)<(x2+w2)) ) {
checkX = true;
}
if ( (y1<y2 && (y1+h1)>y2) || (y1<(y2+h2) && (y1+h1)>y2+h2) || (y1>y2 && (y1+h1)<(y2+h2)) ) {
checkY = true;
}
return checkX && checkY;
}
I hope I'm not confusing you with all this material. I'll try and keep an eye out for any question you may have about these things.
Good luck and have fun!
I'm attempting to use Turtle Graphics to make a fractal via recursion, but for some reason my code seems to not return the Turtle back to the origin.
My code is as follows
public static void sun(Turtle t, double radius) {
for ( int i = 0; i < 360; i++ ) {
t.forward( radius * .0174 );
t.left( 1 );
}
t.penup();
t.left(90);
t.forward(radius);
//t.fill();
t.pendown();
for (int i = 0; i < 8; i++) {
t.forward(2*radius);
t.backward(2*radius);
t.left(45);
}
t.penup();
t.backward(radius);
t.right(90);
t.pendown();
}
public static void fractalSun(Turtle t, double r, int level) {
int color;
if (level == 0) {
t.color(255, 0, 0);
sun(t, r);
}
else {
sun(t, r);
t.left(90);
t.forward(r);
t.right(90);
t.forward(r * 2);
t.right(90);
fractalSun(t, r/4, level -1);
t.left(90);
t.backward(r * 2);
}
}
The code compiles successfully, but produces this image:
Screenshot
My goal would be for the turtle to return to the center of each 'sun' but something isn't working.
Although the sun() method returns the turtle to where it started, the fractalSun() method leaves the turtle to the center of the figure. So whether fractalSun() calls itself or sun() it has to make adjustments. Here's an update fix with fewer changes (mostly deletions):
Change this final block of code in sun():
t.penup();
t.backward(radius);
t.right(90);
t.pendown();
to be simply one statement:
// t.penup();
// t.backward(radius);
t.right(90);
// t.pendown();
Drop three lines of code from fractalSun() and change the arguments to the final function call:
public static void fractalSun(Turtle t, double r, int level) {
if (level == 0) {
t.color(255, 0, 0);
sun(t, r);
} else {
sun(t, r);
// t.left(90);
// t.forward(r);
// t.right(90);
t.forward(r * 2);
t.right(90);
fractalSun(t, r / 4, level - 1);
t.left(90);
t.backward(r * 2 + r / 4); // added a term to the equation
}
}
OUTPUT
Note: I simulated this using Python turtle so you may need to tweak my Java code if it's amiss.
Your 8-spoke loop leaves the pen at the center of the figure after each spoke. At the end of the loop, starting at the center, you execute this sequence:
t.penup();
t.backward(radius);
t.right(90);
t.pendown();
In particular, you back up one radius; I think that's where you're getting off your intended point. Drop that line, double-check your desired direction, and I think you'll be okay.
I'm trying to write a formula to pan the camera enough so that the center point of an object is just visible at the edge of the screen.
So, in other words if the object is out of view to the right, I would change the x and y position of the camera, so that the object is just at the right edge of the screen (without changing camera angle or z co-ordinate).
Can anyone give me any hints how to do this?
I figured out a solution that serves my purpose, but the only way I could do it was by modifying the camera height (which is not exactly what I wanted):
// note: pos is the center of the object that is to appear at edge of screen
// m_position is the 3d position of the camera
// m_plane[] is array of left, right, etc. planes of camera fustrum
void Camera::PanTo(const Vector3D& pos)
{
int n;
Vector3D vectorNearest;
for (n = 0; n < NUM_PLANES; n++)
{
if (m_plane[n].GetDistance(pos) < 0)
{
m_plane[n].Normalize();
vectorNearest += m_plane[n].GetVectorNearest(pos);
}
}
m_posDesire.m[IX_X] = m_position.m[IX_X] + vectorNearest.m[IX_X];
m_posDesire.m[IX_Y] = m_position.m[IX_Y] + vectorNearest.m[IX_Y];
m_posDesire.m[IX_Z] = m_position.m[IX_Z] + vectorNearest.m[IX_Z];
}
// This is the definition of the Plane class:
class Plane
{
public:
void Normalize()
{
float lenInv = 1.0f/sqrtf(m_a*m_a + m_b*m_b + m_c*m_c);
m_a *= lenInv;
m_b *= lenInv;
m_c *= lenInv;
m_d *= lenInv;
}
float GetDistance(const Vector3D& pos) const
{
return m_a*pos.m[IX_X] + m_b*pos.m[IX_Y] +
m_c*pos.m[IX_Z] + m_d;
}
Vector3D GetVectorNearest(const Vector3D& pos) const
{
Vector3D normal(m_a, m_b, m_c);
float posDotNormal = pos.dotProduct(normal);
Vector3D nearest = normal*(m_d+posDotNormal);
return nearest;
}
float m_a, m_b, m_c, m_d;
};
Can someone please share the algorithm to rotate and resize a QGraphicsLineItem present on a QGraphicsScene? I wish to be able to click on either end of the line and rotate it while the opposite end automatically becomes the anchor point for rotation.
I have tried the solution given below and it works brilliantly!!. The solution is for line rotation only. This solution is provided to me when i posted the question at other Qt platform. All the credit goes to original author who provided the solution to me.
void Line::mousePressEvent( QGraphicsSceneMouseEvent * event ){
const QPointF pos = event->pos();
const qreal l1 = QLineF( pos, this->line().p1() ).length();
const qreal l2 = QLineF( pos, this->line().p2() ).length();
const qreal threshold = 3.5;
if( l1 < l2 and l1 < threshold ){
_dragIndex = 1;
} else if ( l2 < l1 and l2 < threshold ){
_dragIndex = 0;
} else{
_dragIndex = -1;
}
event->setAccepted( _dragIndex != -1 );
}
void Line::mouseMoveEvent( QGraphicsSceneMouseEvent * event ){
if( _dragIndex != -1 ){
const QPointF anchor = _dragIndex == 0 ? this->line().p1() : this->line().p2();
QLineF ma = QLineF(anchor,event->pos());
ma.setLength( line().length() );
const QPointF rotated = anchor + QPointF( ma.dx(), ma.dy() );
this->setLine( _dragIndex == 0 ? QLineF(anchor,rotated) : QLineF(rotated,anchor) );
}
}
void Line::mouseReleaseEvent( QGraphicsSceneMouseEvent * event ){
_dragIndex = -1;
QGraphicsLineItem::mouseReleaseEvent(event);
}
1- Overload mouseMoveEvent of your scene. Make sure you are in the initial state, no clicks, nothing. If position is close enough to the ends, set your flag as such.
// scene.cpp
void mouseMoveEvent(QMouseEvent *e){
if(moveToRotate){
lineItem->rotate(flag, e->pos());
...
return;
}
if(isClose(e->pos(), lineItem->firstEnd)
flag = 1;
else if(isClose(e->pos(), lineItem->secondEnd)
flag = 2;
else
flag = 0;
return;
}
2- Overload mouseClickEvent of the scene. If flag is set (1 or 2), get your anchor point. You can overload paint method of lineItem to highlight the end point. Also set firstClick flag.
void mouseClickEvent(QMouseEvent *e){ // firstClick happened
if(flag !=0){ //process click
firstClick = true;
paintAnchor = true;
moveToRotate = true;
}
else // neglect click
return;
return;
}
// myCustomLineItemclassThatInheritsQGraphicsLineItem.cpp
void paint(... ){
if(paintAnchor){
...
}
}
There are obvious errors, but the general flow should be as such. You may need a signal to connect the boolean to the paint event of another class. You may need to overload mouseReleaseEvent to properly set moveToRotate. And, of course rotate and isClose methods are yours to be written -maybe even exist in the API.
Just construct the main flowchart, it will help you a lot.
I am new to java. i created a program to find the area of polygons.
I wanted it to ask the type of polygon an then find the area. i used if, else if and else statements
but whenever i type the name of the polygon nothing happens.
Here is the script
import java.util.Scanner ;
public class Area
{
static Scanner sc = new Scanner(System. in );
public static void main(String[] args) {
System.out.print("Enter the type of polygon: ");
String polygon = new String("polygon");
polygon = sc.next();
String square = new String("square");
String rectangle = new String("rectangle;");
String triangle = new String("triangel");
polygon = sc.next();
if (polygon == square) {
double side;
System.out.print("Enter the side: ");
side = sc.nextDouble();
double area;
area = side * side;
System.out.print("The Area is: " + area);
} else if (polygon == rectangle) {
double length;
double breadth;
System.out.print("Enter the length: ");
length = sc.nextDouble();
System.out.print("Enter the breadth: ");
breadth = sc.nextDouble();
double area;
area = length * breadth;
System.out.print("The Area is : " + area);
} else if (polygon == triangle) {
double base;
double height;
System.out.print("Enter the base: ");
base = sc.nextDouble();
System.out.print("Enter the height: ");
height = sc.nextDouble();
Double area;
area = base * height / 2;
System.out.print("The Area is: " + area);
} else {
System.out.print("ERROR it is not a polygon");
}
}
}
Please help me out
thank you
Okay, I see a couple of better ways to do things in your code.
You do not need to create a String object just to compare your input to the string. You could just use:
if(polygon="square")
Or even better you could use the switch statement. I think the reason you are running into an issue is because you are using .next() instead of .nextLine(). I would use a switch statement and do the following:
Scanner sc = new Scanner(System. in );
myInput = sc.nextLine() // Get the next line from the keyboard
switch (myInput.toLowerCase()) // Make the inputted text to lower case, do switch
{
case "square":
// DO SQUARE LOGIC HERE
break;
case "rectangle":
// DO RECT LOGIC HERE
break;
case "triangle":
// DO TRIANGLE LOGIC HERE
break;
default:
// Did not recognize the type of polygon entered.
}
it seems you are comparing the variable polygon(which always holds the string "polygon") to the next line.
try this:
import java.util.Scanner;
public class Area
{
static Scanner sc = new Scanner(System.in);
public static void main (String [] args)
{
System.out.println("To find the area of a polygon type,");
System.out.println("\"1\" for a Square");
System.out.println("\"2\" for a Rectangle");
System.out.println("\"3\" for a Triangle");
System.out.println("Enter the number to select the type of polygon: ");
int p = sc.nextInt();
if (p == 1 ) {
double side ;
System.out.print("Enter the squaer side: ");
side =sc.nextDouble() ;
double area;
area =side * side;
System.out.print("The Area is: " + area);}
else if (p == 2)
{
double length;
double breadth;
System.out.print("Enter the rectangle length: ");
length =sc.nextDouble();
System.out.print("Enter the breadth: ");
breadth =sc.nextDouble();
double area;
area =length * breadth;
System.out.print("The Area is : " + area); }
else if (p == 3)
{
double base;
double height;
System.out.print("Enter the triangle's base: ");
base =sc.nextDouble();
System.out.print("Enter the height: ");
height =sc.nextDouble();
Double area ;
area = base * height / 2 ;
System.out.print("The Area is: " + area) ; }
else
{
System.out.println("ERROR it is not a polygon");
System.out.print("Please enter a number: 1, 2 or 3.");
}
}
}
I've tried it a few times and it works fine. hope this looks better for your coding as well as it is "user-friendlier" in my opinion because the programmer would ask a user for numbers instead of strings (which may cause miss-spelling). good luck.