I'm quite new to programming/Unity and trying to figure out how to use the OnGUI horizontal slider.
I've got three sliders range 0-100 and want a value named pointsLeft to increase/decrease when the user moves the sliders. Also the total value of the three sliders can't be over 100. I would really appreciate it if someone could help a newbie! See code for more details.
using UnityEngine;
using System.Collections;
public class Slider : MonoBehaviour {
public float sliderA = 0.0f;
public float sliderB = 0.0f;
public float sliderC = 0.0f;
public float startingPoints = 100f;
public float pointsLeft;
void Start() {
pointsLeft = startingPoints;
}
void OnGUI () {
GUI.Label(new Rect(250, 10, 100, 25), "Points Left: " + pointsLeft.ToString());
GUI.Label (new Rect (25, 25, 100, 30), "Strength: " + sliderA.ToString());
sliderA = GUI.HorizontalSlider (new Rect (25, 50, 500, 30), (int)sliderA, 0.0f, 100.0f);
GUI.Label (new Rect (25, 75, 100, 30), "Agility: " + sliderB.ToString());
sliderB = GUI.HorizontalSlider (new Rect (25, 100, 500, 30), (int)sliderB, 0.0f, 100.0f);
GUI.Label (new Rect (25, 125, 100, 30), "Intelligence: " + sliderC.ToString());
sliderC = GUI.HorizontalSlider (new Rect (25, 150, 500, 30), (int)sliderC, 0.0f, 100.0f);
/*if(sliderA < pointsLeft) {
pointsLeft = (int)pointsLeft - sliderA; //this is not doing the magic
}
*/
//decrease pointsLeft when the slider increases or increase pointsLeft if slider decreases
//store the value from each slider when all points are spent and the user pressess a button
}
}
Don't update the slider value until you are sure the slider move is valid.
Below, this code stores the new slider values in temp variables, and if the value is below the points allowed then it allows the change:
public float pointsMax = 100.0f;
public float sliderMax = 100.0f;
public float pointsLeft;
void OnGUI () {
// allow sliders to update based on user interaction
float newSliderA = GUI.HorizontalSlider(... (int)sliderA, 0.0f, sliderMax);
float newSliderB = GUI.HorizontalSlider(... (int)sliderB, 0.0f, sliderMax);
float newSliderC = GUI.HorizontalSlider(... (int)sliderC, 0.0f, sliderMax);
// only change the sliders if we have points left
if ((newSliderA + newSliderB + newSliderC) < pointsMax) {
// Update the current values for the sliders to use next time
sliderA = newSliderA;
sliderB = newSliderB;
sliderC = newSliderC;
}
// record the new points count
pointsLeft = pointsMax - (sliderA + sliderB + sliderC);
}
Related
I was testing my app on android,
my app have 1 background image with 2 animations using TextureAtlas
it works fine on desctop, the sprite and the animations all scale but when I teste it on android, the sprite resize corretly but the animations dont resize at all
constantes.VIRTUAL_WIDTH=1920;
constantes.VIRTUAL_HEIGHT=1080;
.....
public static void show() {
camera = new OrthographicCamera(constantes.VIRTUAL_WIDTH, constantes.VIRTUAL_HEIGHT); //Aspect Ratio Maintenance
batch = new SpriteBatch();
texturafundo = new Texture("cenarios/penhasco.jpg");
spriteFundo = new Sprite(texturafundo);
spriteFundo.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
// animations
textureAtlas = new TextureAtlas(Gdx.files.internal("anima/rio.txt"));
animacao = new Animation(1/10f, textureAtlas.getRegions());
textureAtlas2 = new TextureAtlas(Gdx.files.internal("anima/portal.txt"));
animacao2 = new Animation(1/10f, textureAtlas2.getRegions());
}
public void render(float delta) {
// update camera
camera.update();
// set viewport
Gdx.gl.glViewport((int) viewport.x, (int) viewport.y,
(int) viewport.width, (int) viewport.height);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
elapsedTime+=delta;
batch.begin();
spriteFundo.draw(batch);
//sesenha animacao 1
batch.draw(animacao.getKeyFrame(elapsedTime, true), 0, 0);
batch.draw(animacao2.getKeyFrame(elapsedTime, true), 788, 249);
batch.end();
}
public void resize(int width, int height) {
float aspectRatio = (float)width/(float)height;
float scale = 1f;
Vector2 crop = new Vector2(0f, 0f);
if(aspectRatio > constantes.ASPECT_RATIO) {
scale = (float) height / (float) constantes.VIRTUAL_HEIGHT;
crop.x = (width - constantes.VIRTUAL_WIDTH * scale) / 2f;
} else if(aspectRatio < constantes.ASPECT_RATIO) {
scale = (float) width / (float) constantes.VIRTUAL_WIDTH;
crop.y = (height - constantes.VIRTUAL_HEIGHT * scale) / 2f;
} else {
scale = (float) width / (float) constantes.VIRTUAL_WIDTH;
}
float w = (float) constantes.VIRTUAL_WIDTH * scale;
float h = (float) constantes.VIRTUAL_HEIGHT * scale;
viewport = new Rectangle(crop.x, crop.y, w, h);
}
I am using a while loop, rotate and translate in order to get the effect I want for my program. I want to be able to contain the loop within the boundaries of the sketch. Can anyone explain to me how that can be done, please?
Here is the code:
float x, y, r, g, b, radius;
void setup()
{
size(800, 700);
smooth();
frameRate(15);
}
void draw()
{
handleRedBox();
}
void handleRedBox() {
background(255);
stroke(255, 0, 0);
color from = color(100, random(255), 2);
color to = color(0, 200, 0);
color interA = lerpColor (to, from, .44);
int x = 100;
while (x < width/2 || x> width/2 ) {
int y = 100;
while (y <height/2 || y > height/2) {
blendMode(DIFFERENCE);
noStroke();
fill(interA);
quadstuff();
strokeWeight(5);
stroke(0, random(255), 0);
line(width/2, height/2, mouseY, mouseX);
translate(width, height);
rotate(radians(frameCount));
y = y + 50;
}
x = x + 50;
}
ghostcirc();
ghostcirc2();
}
void ghostcirc() {
int w = 0;
while (w < width) {
int q = 0;
while (q <height) {
blendMode(ADD);
fill(random(61), random(90), random(250));
ellipse(255, 255, 100, 100);
;
noStroke();
translate(width, height);
rotate(radians(frameCount));
q = q + 100;
}
w = w + 50;
}
}
void ghostcirc2() {
for (int w= 0; w < width; w+=10) {
blendMode(ADD);
fill(random(61), random(90), random(250));
ellipse(50, 50, 75, 75);
;
noStroke();
translate(width, height);
rotate(radians(frameCount));
//if (keyPressed == true){
// fill(random(100), random(90), random(250));
}
}
void quadstuff() {
int rad = 60; // Width of the shape
float xpos, ypos; // Starting position of shape
float xspeed = 2.8; // Speed of the shape
float yspeed = 2.2; // Speed of the shape
xpos = width/2;
ypos = height/2;
//ellipse(mouseX+x, mouseY+y, 100,100);
quad(xpos, ypos, rad, rad, mouseX+rad, mouseY+rad, xspeed, yspeed);
stroke(0);
strokeWeight(5);
}
Your question is still pretty broad, and that's still a lot of code to try to debug. But I appreciate that you went through the trouble of narrowing it down, so I'm going to try to help in general terms.
Your code involves a lot of stuff that I don't really understand, so I'm going to start with a simpler example. Honestly you might be better off doing the same- start over with something more basic, and add the bounding logic from the beginning. That's going to be much easier than trying to add it in after you've already written everything.
So, there are two main ways to do this type of animation in Processing. I'll cover both.
Option 1: Rely on translate() and rotate() to position stuff for you.
This is what your code does. Here is a simpler example that shows an ellipse rotating around the mouse position:
float angle = 0;
void setup() {
size(500, 500);
}
void draw() {
angle+=.1;
background(0);
translate(mouseX, mouseY);
rotate(angle);
translate(100, 0);
ellipse(0, 0, 50, 50);
}
Now, if you want to bound the ellipse to stay inside the window, first you need to determine where the ellipse will be on the screen. This could be complicated since we're using the translate() and rotate() functions, which are a little like moving the camera instead of moving the ellipse- the ellipse "thinks" it's still at position 0,0. So we need to get the position of the ellipse after we move the camera. Luckily Processing gives us the screenX() and screenY() functions:
float screenX = screenX(0, 0);
float screenY = screenY(0, 0);
This will tell us where on the screen the ellipse will be drawn (or more accurately, where position 0,0 will be after the transforms are applied). We can use this to check whether these go outside the bounds of the window, and then do whatever bounding you want.
Exactly what type of bounding you do depends on what you want to happen. You could wrap the animation around the screen so that when it goes off the right side it reappears on the left side. You could limit the positions so they only go to the border of the window instead of moving past it. Here is that:
float angle = 0;
void setup() {
size(500, 500);
}
void draw() {
angle+=.1;
background(0);
translate(mouseX, mouseY);
rotate(angle);
translate(100, 0);
float screenX = screenX(0, 0);
float screenY = screenY(0, 0);
if (screenX < 25) {
rotate(-angle);
translate(25-screenX, 0);
rotate(angle);
} else if (screenX > 475) {
rotate(-angle);
translate(475-screenX, 0);
rotate(angle);
}
if (screenY < 25) {
rotate(-angle);
translate(0, 25-screenY);
rotate(angle);
} else if (screenY > 475) {
rotate(-angle);
translate(0, 475-screenY);
rotate(angle);
}
ellipse(0, 0, 50, 50);
}
This code is the same as above, except now it uses screenX() and screenY() to determine when the ellipse will be off the screen, and then uses translate() to move it back inside the bounds of the screen.
Option 2: Keep track of the position yourself.
Instead of relying on translate() and rotate() to do the positioning for you, you could also just use some basic algebra and trig to do the positioning yourself.
Here is the simple program, without bounding yet:
float angle = 0;
void setup() {
size(500, 500);
}
void draw() {
angle+=.1;
background(0);
float circleX = mouseX + cos(angle)*100;
float circleY = mouseY + sin(angle)*100;
ellipse(circleX, circleY, 50, 50);
}
Notice that I'm calculating the position of the ellipse myself instead of relying on translate() and rotate(). Now it might be easier to think about exactly where the circle will be, so I can do the bounding:
float angle = 0;
void setup() {
size(500, 500);
}
void draw() {
angle+=.1;
background(0);
float circleX = mouseX + cos(angle)*100;
float circleY = mouseY + sin(angle)*100;
if (circleX < 25) {
circleX = 25;
} else if (circleX > 475) {
circleX = 475;
}
if (circleY < 25) {
circleY = 25;
} else if (circleY > 475) {
circleY = 475;
}
ellipse(circleX, circleY, 50, 50);
}
This might be a little easier to think about, since you can work with the screen coordinates directly. Both options do the same thing, they're just different ways of thinking about it.
From here it's just a matter of defining exactly how your bounding should work. I've given you one example, but you could do anything you want.
You might also want to restrict your input variables (in my case, mouseX and mouseY) so the animation never leaves the window. Adding this at the top of the draw() function of either one of the above options will prevent the animation from leaving the screen:
if (mouseX < 150) {
mouseX = 150;
} else if (mouseX > 350) {
mouseX = 350;
}
if (mouseY < 150) {
mouseY = 150;
} else if (mouseY > 350) {
mouseY = 350;
}
Again, how you do this is really up to you and what you want to happen. It will probably be easier if you start over with a basic program like mine and then add one small thing at a time instead of trying to add it to your existing huge sketch. Good luck.
I was reading the book The Nature of Code, where Exercise 3.12 asked me to implement a double pendulum.
class Pendulum {
PVector origin, location;
float r; // arm length
float angle;
float aVelocity;
float aAcceleration;
float damping;
Pendulum(PVector origin_, float r_) {
origin = origin_.get();
location = new PVector();
r = r_;
angle = PI/3;
aVelocity = 0;
aAcceleration = 0;
damping = 0.995;
}
void go() {
update();
display();
}
void update() {
float gravity = 0.4;
aAcceleration = (-1 * gravity / r) * sin(angle);
aVelocity += aAcceleration;
angle += aVelocity;
aVelocity *= damping;
location.set(r*sin(angle), r*cos(angle));
location.add(origin);
}
void display() {
stroke(0);
line(origin.x, origin.y, location.x, location.y);
fill(150);
ellipse(location.x, location.y, 20, 20);
}
}
Pendulum p, p2;
void setup() {
size(640, 360);
p = new Pendulum(new PVector(width/2, 0), 150);
p2 = new Pendulum(p.location, 100);
}
void draw() {
background(255);
p.go();
p2.go();
}
So in the setup function, I set the origin of p2 to be the location of p1. However, the origin of p2 appeared on the position (0, 0). How should I fix this? I have tried to set a temporary variable for p2 but that's not convenient.
I'm not exactly sure what you are trying to do,
but in the constructor:
Pendulum(PVector origin_, float r_) {
origin = origin_.get();
location = new PVector(); <-- here you set the location to a new vector
...
}
And you directly use the location in here:
void setup() {
size(640, 360);
p = new Pendulum(new PVector(width/2, 0), 150);
p2 = new Pendulum(p.location, 100); <-- here
}
which is the new location created. i suppose that's your problem you should be looking into.
I have recently started up a 3d first person shooter game in Monogame and I am having some issues with the camera controls, I am unable to figure out how I make the camera slowly turn on it's X axis when I hold down the left/right arrow keys.
At the minute, the code I have is as follows:
Matrix view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(0, 0, 0), Vector3.UnitZ);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 600f, 0.1f, 100f);
And then down in the update section I have this:
if (kb.IsKeyDown(Keys.Left))
{
view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(-2, -2, -2), Vector3.UnitZ);
}
The issue is at the minute this code simply moves the camera to the side a little then stops. I am unsure on how to keep having it move until I let go of the key?
The entire of my code will be shown below incase I forgot something (the floor verts currently don't work and the names related to a ship is due to me working from a tutorial):
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game1
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Model model;
Vector3 ship1Location = new Vector3(40, 0, 0);
Vector3 ship2Location = new Vector3(20, 0, 0);
Matrix view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(0, 0, 0), Vector3.UnitZ);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 600f, 0.1f, 100f);
VertexPositionTexture[] floorVerts;
BasicEffect effect;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
floorVerts = new VertexPositionTexture[6];
floorVerts[0].Position = new Vector3(-20, -20, 0);
floorVerts[1].Position = new Vector3(-20, 20, 0);
floorVerts[2].Position = new Vector3(20, -20, 0);
floorVerts[3].Position = floorVerts[1].Position;
floorVerts[4].Position = new Vector3(20, 20, 0);
floorVerts[5].Position = floorVerts[2].Position;
effect = new BasicEffect(graphics.GraphicsDevice);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
model = Content.Load<Model>("health2");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
Matrix ship1WorldMatrix = Matrix.CreateTranslation(ship1Location);
Matrix ship2WorldMatrix = Matrix.CreateTranslation(ship2Location);
if (IsCollision(model, ship1WorldMatrix, model, ship2WorldMatrix))
{
ship1Location = new Vector3(0, -20, 0);
}
KeyboardState kb = Keyboard.GetState();
if (kb.IsKeyDown(Keys.A))
{
ship1Location += new Vector3(-0.1f, 0, 0);
}
if (kb.IsKeyDown(Keys.Left))
{
view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(-2, -2, -2), Vector3.UnitZ);
}
ship2Location += new Vector3(0, 0, 0);
base.Update(gameTime);
}
private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
{
for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++)
{
BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere;
sphere1 = sphere1.Transform(world1);
for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++)
{
BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere;
sphere2 = sphere2.Transform(world2);
if (sphere1.Intersects(sphere2))
return true;
}
}
return false;
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
DrawGround();
Matrix ship1WorldMatrix = Matrix.CreateTranslation(ship1Location);
Matrix ship2WorldMatrix = Matrix.CreateTranslation(ship2Location);
DrawModel(model, ship1WorldMatrix, view, projection);
DrawModel(model, ship2WorldMatrix, view, projection);
base.Draw(gameTime);
}
void DrawGround()
{
// The assignment of effect.View and effect.Projection
// are nearly identical to the code in the Model drawing code.
float aspectRatio =
graphics.PreferredBackBufferWidth / (float)graphics.PreferredBackBufferHeight;
float fieldOfView = Microsoft.Xna.Framework.MathHelper.PiOver4;
float nearClipPlane = 1;
float farClipPlane = 200;
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
fieldOfView, aspectRatio, nearClipPlane, farClipPlane);
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
graphics.GraphicsDevice.DrawUserPrimitives(
// We’ll be rendering two trinalges
PrimitiveType.TriangleList,
// The array of verts that we want to render
floorVerts,
// The offset, which is 0 since we want to start
// at the beginning of the floorVerts array
0,
// The number of triangles to draw
2);
}
}
private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.AmbientLightColor = new Vector3(2f, 0, 0);
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
}
}
Since the camera's position and the point it is looking at are necessary parameters to create a view matrix, you can simply rotate (think orbit) the LookAt camLookAt around the camPosition like this:
//declare class scope variables
Vector3 camPosition = new Vector3(60, 20, 10);//your starting camera position
Vector3 camLookAt = Vector3.Zero;//your starting camera focus point (look at)
Vector2 camUp = Vector3.Up;
float camYawRate = 0.004f;//set to taste
//in the Update method
float elapsed = gameTime.ElapsedGameTime.TotalSeconds;
//later in the method...
if (kb.IsKeyDown(Keys.Left))
{
camLookAt = Vector3.Transform(camLookAt - camPosition,Matrix.CreateRotationY(-camYawRate * elapsedTime)) + camPosition;);//remove the - sign from camYawRate to rotate to the right (or vice versa)
view = Matrix.CreateLookAt(camPosition, camLookAt, camUp);
}
And that's it, give it a shot. Add another similar block to rotate to the right.
I'm trying to do something similar to what is asked in this question, but I don't really understand the answer given to that question and I'm not sure if it is what I need.
What I need is simple, though I'm not so sure it's easy. I want to calculate the number of pixels on the screen that are a certain color. I understand that each 'pixel' that we see is actually a combination of pixels of different colors that appear to be, say, green. So what I need is that actual color- the one that the user sees.
For example, if I created a UIView, set the background color to [UIColor greenColor], and set its dimensions to half of the area of the screen (we can assume that the status bar is hidden for simplicity and that we are on an iPhone), I would expect this 'magic method' to return 240 * 160 or 38,400- half the area of the screen.
I don't expect anyone to write out this 'magic method,' but I'd like to know
a) If this is possible
b) If so, if it be done in almost-realtime
c) If so again, where to start. I've heard it can be done with OpenGL, but I have no experience in that area.
Here is my solution, thanks to Radif Sharafullin:
int pixelsFromImage(UIImage *inImage) {
CGSize s = inImage.size;
const int width = s.width;
const int height = s.height;
unsigned char* pixelData = malloc(width * height);
int pixels = 0;
CGContextRef context = CGBitmapContextCreate(pixelData,
width,
height,
8,
width,
NULL,
kCGImageAlphaOnly);
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextDrawImage(context, CGRectMake(0, 0, width, height), inImage.CGImage );
CGContextRelease(context);
for(int idx = 0; idx < width * height; ++idx) {
if(pixelData[idx]) {
++pixels;
}
}
free(pixelData);
return pixels;
}
it is possible. I've done something similar to calculate the percentage of transparent pixels, but since I needed the rough estimate, I was not looking at each pixel but at every tenth pixel, step variable in the code below.
BOOL isImageErased(UIImage *inImage, float step, int forgivenessCount){
CGSize s = inImage.size;
int width = s.width;
int height = s.height;
unsigned char* pixelData = malloc( width * height );
int forgivenessCounter=0;
CGContextRef context = CGBitmapContextCreate ( pixelData,
width,
height,
8,
width,
NULL,
kCGImageAlphaOnly );
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextDrawImage( context, CGRectMake(0, 0, width, height), inImage.CGImage );
CGContextRelease( context );
for (int x=0; x<width; x=x+step) {
for (int y=0; y<height; y=y+step) {
if(pixelData[y * width + x]) {
forgivenessCounter++;
if (forgivenessCounter==forgivenessCount) {
free(pixelData);
return FALSE;
}
};
}
}
free( pixelData );
return TRUE;}
I believe this code can be used for your purpose if you pass a preprocessed grayscaled image or modify the kCGImageAlphaOnly setting of the API.
Hope that helps
eric.mitchell solution written in Swift 3
func pixelsFromImage(inImage: UIImage) -> Int {
let width = Int(inImage.size.width)
let height = Int(inImage.size.height)
let bitmapBytesPerRow = width
let bitmapByteCount = bitmapBytesPerRow * height
let pixelData = UnsafeMutablePointer<UInt8>.allocate(capacity: bitmapByteCount)
let colorSpace = CGColorSpaceCreateDeviceGray()
let context = CGContext(data: pixelData,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: bitmapBytesPerRow,
space: colorSpace,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.alphaOnly.rawValue).rawValue)!
let rect = CGRect(x: 0, y: 0, width: width, height: height)
context.clear(rect)
context.draw(inImage.cgImage!, in: rect)
var pixels = 0
for x in 0...width {
for y in 0...height {
if pixelData[y * width + x] > 0 {
pixels += 1
}
}
}
free(pixelData)
return pixels
}